package com.example.common.rc.aop.dicttrans.classutil;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import java.io.File;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.SneakyThrows;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;

/**
 * 字节码工具类
 *
 * @author zjarlin
 * @since 2023/01/12
 */
public class ByteBuddyUtil {
    public static <T> Class<? extends T> genChildClass(List<String> needAddFields, final Class<T> superClass) {
        return genChildClass(needAddFields, superClass, String.class);
    }

    public static <T> Class<? extends T> genChildClass(List<String> needAddFields, final Class<T> superClass, final Type type) {
        if (CollUtil.isEmpty(needAddFields)) {
            return superClass;
        }
        DynamicType.Builder<T> subclass = new ByteBuddy().subclass(superClass);
        DynamicType.Builder<T> tOptional = null;
        for (String needAddField : needAddFields) {
            //defineProperty会生成GetterAndSetter
            subclass = subclass.defineProperty(needAddField, type);
        }
        return subclass.withToString()
            .make().load(superClass.getClassLoader()).getLoaded();
    }

    public static <T> Class<? extends T> genChildClass(Map<String, Type> needAddFields, final Class<T> superClass) {
        if (CollUtil.isEmpty(needAddFields)) {
            return superClass;
        }
        DynamicType.Builder<T> subclass = new ByteBuddy().subclass(superClass);
        DynamicType.Builder<T> tOptional = null;
        Set<Map.Entry<String, Type>> entries = needAddFields.entrySet();
        for (Map.Entry<String, Type> entry : entries) {
            String needAddField = entry.getKey();
            Type type = entry.getValue();

            subclass = subclass.defineProperty(needAddField, type);
        }
        Class<? extends T> loaded = subclass.withToString()
            //                .withHashCodeEquals()
            .make().load(superClass.getClassLoader()).getLoaded();
        return loaded;
    }

    @SneakyThrows
    private static <T> Map<TypeDescription, File> genChildClass2(List<String> needAddFields, final Class<T> superClass) {
        String s = superClass.getSimpleName() + "$Pro";
        String packagePath = ClassUtil.getPackagePath(ByteBuddyUtil.class);

        File file = new File(packagePath + File.separator + s);
        DynamicType.Builder<T> subclass = new ByteBuddy().subclass(superClass);

        for (String needAddField : needAddFields) {
            subclass = subclass.defineProperty(needAddField, String.class);
        }
        Map<TypeDescription, File> typeDescriptionFileMap = subclass.withToString().withHashCodeEquals().make().load(superClass.getClassLoader()).saveIn(file);
        return typeDescriptionFileMap;
    }

}
